﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using VSTranslator.Translation;

namespace VSTranslator.Adornment
{
    internal class TranslationAdornmentManager
    {
        private IWpfTextView View;
        private IAdornmentLayer Layer;       
		private ITextBuffer Buffer;
		public IList<TranslationAdornment> Translations = new List<TranslationAdornment>();

        private TranslationAdornmentManager(IWpfTextView view)
        {
			View = view;
			View.LayoutChanged += OnLayoutChanged;
			View.Closed += OnClosed;
			Buffer = View.TextBuffer;			
			Buffer.Changed += OnBufferChanged;            	

			Layer = view.GetAdornmentLayer("TranslationAdornmentLayer");
        }

        public static TranslationAdornmentManager Create(IWpfTextView view)
        {
            return view.Properties.GetOrCreateSingletonProperty<TranslationAdornmentManager>(delegate { return new TranslationAdornmentManager(view); });
        }

		private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
		{
			ClearTranslations();
			View.VisualElement.Focus();
		}		  

        private void OnClosed(object sender, EventArgs e)
        {			
			Buffer.Changed -= OnBufferChanged;			
            View.LayoutChanged -= OnLayoutChanged;
            View.Closed -= OnClosed;
			ClearTranslations();
        }
		
        private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {            
            HashSet<TranslationAdornment> newPosts = new HashSet<TranslationAdornment>();
			          
            foreach (Span span in e.NewOrReformattedSpans)
            {
				List<TranslationAdornment> adornments = GetTranslations(new SnapshotSpan(View.TextSnapshot, span));
				foreach (TranslationAdornment adornment in adornments)
				{
					if (!newPosts.Contains(adornment))
					{
						newPosts.Add(adornment);
						RenderTranslation(adornment);
					}
				}               
            }          
        }

		private void ClearTranslations()
		{
			for (int i = Translations.Count - 1; i >= 0; i--) {
				RemoveTranslation(Translations[i]);
			}			
		}

        private void RenderTranslation(TranslationAdornment translation)
        {          
            SnapshotSpan span = translation.Span.GetSpan(View.TextSnapshot);
            Geometry g = View.TextViewLines.GetMarkerGeometry(span);

            if (g != null)
            {						
				translation.Margin = new Thickness(g.Bounds.BottomLeft.X, g.Bounds.BottomLeft.Y, 0, 0);              
				Layer.AddAdornment(span, null, translation);			
            }            
        }

		public void AddTranslation(SnapshotSpan span, TranslationRequest request)
		{
			ClearTranslations();
			TranslationAdornment a = new TranslationAdornment(span, request);			
			Translations.Add(a);
			a.AdornmentClosed += OnTranslationClosed;
			RenderTranslation(a);
		}

		private void RemoveTranslation(TranslationAdornment a)
		{
			a.DetachRequest();
			Translations.Remove(a);
			Layer.RemoveAdornment(a);
		}

		/// <summary>
		/// gets translations attached to this SnapshotSpan
		/// </summary>
		public List<TranslationAdornment> GetTranslations(SnapshotSpan span)
		{
			List<TranslationAdornment> res = new List<TranslationAdornment>();
			foreach (TranslationAdornment t in Translations)
			{
				if (t.Span.GetSpan(span.Snapshot).OverlapsWith(span))
					res.Add(t);
			}
			return res;
		}

		private void OnTranslationClosed(object sender, EventArgs e)
		{
			RemoveTranslation((TranslationAdornment)sender);
		}

    }
}

